8장. AI API의 기본 구조
1. AI API를 사용한다는 것은 무엇인가
지금까지는 ChatGPT 같은 화면에서 AI에게 질문하는 방식으로 설명했다.
하지만 실제 서비스를 만들려면 사용자가 직접 ChatGPT 화면에 들어가서 질문하게 만들 수는 없다.
예를 들어 우리 서비스에 이런 기능을 넣고 싶다고 해보자.
- 고객 문의를 자동 요약한다.
- 관리자 페이지에서 신고 내용을 AI가 정리해준다.
- 사용자가 입력한 문장을 자동 번역한다.
- 코드 리뷰 결과를 PR 댓글로 남긴다.
- 사내 문서를 검색해서 답변하는 챗봇을 만든다.
이런 기능을 만들려면 서비스 서버에서 AI 모델을 호출해야 한다.
이때 사용하는 것이 AI API다.
API는 프로그램과 프로그램이 서로 통신하기 위한 약속이다.
AI API는 우리 서버가 AI 모델에게 요청을 보내고, AI 모델이 답변을 돌려주는 방식이다.
흐름은 단순하게 보면 다음과 같다.
사용자
→ 우리 서비스
→ 우리 백엔드 서버
→ AI API
→ AI 모델
→ AI 응답
→ 우리 백엔드 서버
→ 사용자
예를 들어 사용자가 관리자 페이지에서 고객 문의 요약 버튼을 누른다고 해보자.
관리자:
"고객 문의 요약" 버튼 클릭
우리 서버:
고객 문의 원문을 가져옴
→ AI API에 요약 요청
→ AI 응답을 받음
→ 관리자 화면에 요약 결과 표시
AI API를 사용하면 AI를 우리 서비스의 기능처럼 붙일 수 있다.
중요한 점은 AI API가 단순히 “질문을 보내면 답이 오는 기능”만은 아니라는 것이다.
운영 환경에서는 다음 요소를 함께 고려해야 한다.
- 어떤 모델을 사용할 것인가
- 어떤 프롬프트를 보낼 것인가
- 응답 형식은 어떻게 받을 것인가
- 응답이 늦으면 어떻게 처리할 것인가
- 비용은 어떻게 제한할 것인가
- 민감 정보는 어떻게 보호할 것인가
- 실패하면 어떻게 재시도할 것인가
- 로그는 어디까지 남길 것인가
AI API를 제대로 이해해야 이후에 챗봇, RAG, AI 자동화, MCP 같은 구조도 안정적으로 만들 수 있다.
API는 Application Programming Interface의 약자다.
쉽게 말하면 프로그램끼리 데이터를 주고받기 위한 약속이다.
AI API는 우리 프로그램이 AI 모델에게 요청을 보내고 응답을 받을 수 있게 해준다.
2. AI API의 기본 요청과 응답 구조
AI API의 기본 구조는 대부분 비슷하다.
우리 서버가 AI API에 요청을 보내고, AI API가 응답을 반환한다.
요청 Request:
- 모델
- 메시지
- 옵션
- 출력 형식
응답 Response:
- AI가 생성한 답변
- 사용된 토큰 수
- 응답 상태
- 에러 정보
예를 들어 다음과 같은 요청이 있다고 해보자.
{
"model": "example-ai-model",
"messages": [
{
"role": "user",
"content": "REST API에서 GET과 POST의 차이를 설명해줘."
}
],
"temperature": 0.2,
"max_tokens": 500
}
이 요청에는 몇 가지 중요한 요소가 있다.
model:
어떤 AI 모델을 사용할지 지정한다.
messages:
AI에게 전달할 대화 내용이다.
temperature:
답변의 다양성을 조절한다.
max_tokens:
AI가 생성할 수 있는 최대 답변 길이를 제한한다.
응답은 대략 다음과 같은 형태로 올 수 있다.
{
"id": "response_123",
"model": "example-ai-model",
"choices": [
{
"message": {
"role": "assistant",
"content": "GET은 주로 데이터를 조회할 때 사용하고, POST는 데이터를 생성하거나 전송할 때 사용합니다."
}
}
],
"usage": {
"input_tokens": 32,
"output_tokens": 41,
"total_tokens": 73
}
}
여기서 실제로 서비스에서 사용할 값은 보통 content다.
"GET은 주로 데이터를 조회할 때 사용하고..."
하지만 운영 관점에서는 usage도 중요하다.
토큰 사용량은 비용과 연결되기 때문이다.
AI API를 서비스에 붙일 때는 답변만 보는 것이 아니라,
요청과 응답 전체 구조를 이해해야 한다.
토큰은 AI가 문장을 처리하는 기본 단위다.
AI API는 보통 입력 토큰과 출력 토큰 사용량을 기준으로 비용이 계산된다.
3. 메시지는 role과 content로 구성된다
대화형 AI API에서는 보통 메시지를 role과 content로 구성한다.
{
"role": "user",
"content": "로그인 API 예시를 만들어줘."
}
여기서 role은 이 메시지를 누가 말했는지 나타낸다.content는 실제 메시지 내용이다.
대표적인 역할은 다음과 같다.
system:
AI가 따라야 할 기본 규칙이나 역할을 지정한다.
user:
사용자가 입력한 요청이다.
assistant:
AI가 이전에 답변한 내용이다.
예를 들어 다음처럼 메시지를 구성할 수 있다.
{
"messages": [
{
"role": "system",
"content": "너는 보안에 민감한 백엔드 개발자다. 답변은 간결하고 실무적으로 작성한다."
},
{
"role": "user",
"content": "로그인 API를 만들 때 주의해야 할 보안 사항을 알려줘."
}
]
}
이 경우 system 메시지는 AI의 기본 태도를 정한다.
user 메시지는 실제 요청이다.
AI는 system 메시지와 user 메시지를 함께 참고해 답변한다.
예를 들어 system 메시지에 다음과 같이 넣을 수 있다.
너는 신입 개발자를 교육하는 강사다.
어려운 용어는 쉽게 풀어서 설명한다.
예시는 Node.js와 MySQL 기준으로 든다.
그러면 이후 user 요청이 짧아도 AI는 이 기준을 참고해서 답변하려고 한다.
JWT 설명해줘.
즉, system 메시지는 “답변의 기본 방향”을 정하는 역할을 한다.
다만 system 메시지가 모든 문제를 해결해주지는 않는다.
상황별 조건, 입력 데이터, 출력 형식은 user 메시지에서 구체적으로 제공하는 것이 좋다.
system 메시지는 AI에게 기본 역할과 규칙을 알려주는 메시지다.
예를 들어 “너는 보안 담당자 관점으로 답변해” 같은 기준을 줄 수 있다.
4. 대화 이력은 어떻게 관리되는가
ChatGPT 화면에서는 이전 대화를 어느 정도 기억하는 것처럼 보인다.
하지만 API에서는 서버가 대화 이력을 직접 관리해야 한다.
AI API는 기본적으로 요청 하나를 받으면 그 요청 안에 들어 있는 메시지를 보고 답한다.
즉, 이전 대화를 이어가려면 이전 메시지를 다시 함께 보내야 한다.
예를 들어 사용자가 처음 이렇게 질문했다고 해보자.
사용자:
로그인 API 만들 때 주의할 점 알려줘.
AI가 답한다.
AI:
비밀번호 해시, 로그인 실패 메시지, 세션 관리, rate limit 등을 고려해야 합니다.
이후 사용자가 다시 묻는다.
사용자:
그중에서 rate limit만 자세히 설명해줘.
사람은 “그중에서”가 이전 답변의 항목을 가리킨다는 것을 안다.
하지만 API 호출에서는 이전 대화가 포함되어 있지 않으면 AI가 문맥을 모를 수 있다.
그래서 서버는 다음처럼 이전 대화를 함께 보내야 한다.
{
"messages": [
{
"role": "user",
"content": "로그인 API 만들 때 주의할 점 알려줘."
},
{
"role": "assistant",
"content": "비밀번호 해시, 로그인 실패 메시지, 세션 관리, rate limit 등을 고려해야 합니다."
},
{
"role": "user",
"content": "그중에서 rate limit만 자세히 설명해줘."
}
]
}
이렇게 하면 AI는 이전 대화를 참고해서 답할 수 있다.
하지만 대화 이력을 계속 모두 보내면 문제가 생긴다.
- 입력 토큰이 계속 증가한다.
- 비용이 증가한다.
- 응답 속도가 느려진다.
- 컨텍스트 한도를 초과할 수 있다.
- 오래된 내용이 현재 답변에 불필요한 영향을 줄 수 있다.
그래서 대화형 서비스를 만들 때는 대화 이력 관리 전략이 필요하다.
대표적인 방식은 다음과 같다.
1. 최근 N개 메시지만 유지한다.
2. 오래된 대화는 요약해서 저장한다.
3. 중요한 사용자 설정만 별도로 저장한다.
4. 현재 질문과 관련 있는 내용만 검색해서 넣는다.
예를 들어 고객센터 AI 챗봇이라면 최근 대화 몇 개는 그대로 유지하고,
이전 대화는 짧게 요약해 넣을 수 있다.
이전 대화 요약:
사용자는 결제 실패 문제를 문의하고 있으며,
카드 결제 시 승인 문자는 받았지만 서비스 내 충전 내역이 반영되지 않았다고 설명했다.
그다음 현재 질문을 함께 보낸다.
현재 사용자 질문:
그럼 언제 처리되나요?
이렇게 하면 긴 대화를 모두 넣지 않아도 문맥을 유지할 수 있다.
컨텍스트 한도는 AI가 한 번에 참고할 수 있는 입력 길이의 제한이다.
대화 이력을 계속 넣으면 이 한도를 초과하거나 비용이 커질 수 있다.
5. temperature는 답변의 다양성을 조절한다
AI API에는 여러 옵션이 있다.
그중 자주 등장하는 옵션이 temperature다.
temperature는 AI 답변의 다양성을 조절하는 값이다.
쉽게 말하면 다음과 같다.
temperature가 낮음:
더 안정적이고 예측 가능한 답변
temperature가 높음:
더 다양하고 창의적인 답변
예를 들어 다음 질문을 보자.
로그인 실패 메시지를 작성해줘.
temperature가 낮으면 다음처럼 일반적이고 안정적인 답변이 나올 가능성이 높다.
이메일 또는 비밀번호가 올바르지 않습니다.
temperature가 높으면 더 다양한 표현이 나올 수 있다.
입력하신 로그인 정보가 일치하지 않습니다.
다시 확인 후 시도해주세요.
둘 다 나쁘지 않다.
하지만 개발 업무에서는 보통 안정성이 중요하다.
특히 다음 작업은 낮은 temperature가 적합하다.
- 코드 생성
- SQL 생성
- JSON 응답 생성
- 기술 문서 요약
- 장애 보고서 정리
- 보안 체크리스트 작성
반대로 다음 작업은 약간 높은 temperature가 도움이 될 수 있다.
- 서비스명 후보 만들기
- 마케팅 문구 작성
- 아이디어 발산
- 이모티콘 문구 생성
- UX 문구 후보 만들기
AI API를 서비스에서 사용할 때는 작업 성격에 따라 옵션을 다르게 줄 수 있다.
코드 리뷰:
temperature 낮게
고객 문의 요약:
temperature 낮게 또는 중간
마케팅 문구 생성:
temperature 중간 이상
아이디어 브레인스토밍:
temperature 높게
temperature가 높다고 무조건 좋은 것은 아니다.
창의성이 필요한 작업에서는 도움이 되지만,
정확성이 중요한 작업에서는 오히려 답변 품질을 떨어뜨릴 수 있다.
temperature는 AI 답변의 다양성을 조절하는 옵션이다.
낮을수록 안정적이고, 높을수록 다양한 답변이 나올 가능성이 커진다.
6. max tokens는 답변 길이를 제한한다
AI API를 사용할 때는 답변 길이도 제어해야 한다.
이때 사용하는 옵션이 max_tokens 또는 비슷한 이름의 출력 제한 옵션이다.
이 옵션은 AI가 생성할 수 있는 최대 토큰 수를 제한한다.
예를 들어 다음 요청을 보자.
아래 회의록을 요약해줘.
max tokens를 작게 설정하면 답변이 짧게 잘릴 수 있다.
회의에서는 신규 AI 요약 기능 도입과 관련해...
중간에 끊겨버리면 실제 서비스에서는 사용할 수 없다.
반대로 너무 크게 설정하면 불필요하게 긴 답변이 나올 수 있다.
비용도 증가한다.
그래서 작업에 맞는 답변 길이를 정해야 한다.
짧은 분류:
50~100 tokens
간단한 요약:
200~500 tokens
보고서 초안:
1,000 tokens 이상
긴 문서 분석:
더 큰 출력 한도 필요
물론 실제 숫자는 모델과 언어, 응답 형식에 따라 달라질 수 있다.
중요한 것은 출력 길이를 무제한으로 두지 않는 것이다.
서비스에서는 보통 다음 이유로 답변 길이를 제한한다.
- 비용 통제
- 응답 속도 개선
- 화면 UI에 맞는 길이 유지
- 너무 장황한 답변 방지
- 비정상적으로 긴 출력 방지
예를 들어 고객 문의 요약 기능에서는 답변이 너무 길 필요가 없다.
요약은 3줄 이내로 작성해줘.
또는 API 옵션으로 출력 토큰을 제한할 수 있다.
{
"max_tokens": 300
}
가장 좋은 방식은 프롬프트와 API 옵션을 함께 사용하는 것이다.
프롬프트:
요약은 3문장 이내로 작성해줘.
API 옵션:
max_tokens를 적절히 제한
이렇게 하면 출력 길이를 더 안정적으로 관리할 수 있다.
7. 스트리밍 응답은 체감 속도를 높인다
AI 답변은 일반 API 응답보다 오래 걸릴 수 있다.
특히 긴 답변을 생성할 때는 몇 초 이상 걸릴 수 있다.
사용자가 버튼을 눌렀는데 화면이 아무 반응 없이 기다리기만 하면 답답하게 느낄 수 있다.
이때 사용할 수 있는 방식이 스트리밍 응답이다.
일반 응답은 AI가 답변을 모두 만든 뒤 한 번에 반환한다.
요청
→ AI가 전체 답변 생성
→ 전체 답변 반환
→ 화면에 표시
스트리밍 응답은 AI가 답변을 생성하는 즉시 조금씩 반환한다.
요청
→ AI가 첫 문장 생성
→ 화면에 표시
→ 다음 문장 생성
→ 화면에 이어서 표시
→ 반복
사용자는 답변이 완성될 때까지 빈 화면을 보는 것이 아니라,
답변이 생성되는 과정을 바로 볼 수 있다.
체감 속도가 좋아진다.
예를 들어 챗봇 UI에서는 스트리밍 응답이 매우 자연스럽다.
AI:
로그인 API를 설계할 때는...
먼저 인증 방식...
그다음 세션 관리...
마지막으로 실패 응답...
문장이 조금씩 나타나면 사용자는 시스템이 동작하고 있다고 느낀다.
스트리밍은 다음 기능에 특히 유용하다.
- AI 챗봇
- 긴 문서 요약
- 코드 설명
- 보고서 초안 작성
- 실시간 대화형 도구
하지만 모든 기능에 스트리밍이 필요한 것은 아니다.
예를 들어 AI가 JSON 결과를 반환하고, 서버가 그 결과를 파싱해서 후속 처리를 해야 한다면 스트리밍이 오히려 복잡할 수 있다.
스트리밍이 적합한 경우:
사용자에게 긴 텍스트를 보여주는 기능
스트리밍이 덜 적합한 경우:
서버 내부에서 JSON 결과를 받아 후속 로직을 처리하는 기능
스트리밍을 적용하면 프론트엔드와 백엔드 구현도 조금 복잡해진다.
- 응답을 chunk 단위로 처리해야 한다.
- 중간에 연결이 끊겼을 때 처리해야 한다.
- 사용자가 중지 버튼을 눌렀을 때 요청을 취소해야 한다.
- 생성 중인 텍스트를 UI에 계속 반영해야 한다.
그래도 사용자에게 AI 답변을 직접 보여주는 서비스라면 스트리밍은 매우 유용한 UX 개선 방법이다.
스트리밍 응답은 답변을 모두 만든 뒤 한 번에 보내는 것이 아니라, 생성되는 대로 조금씩 보내는 방식이다.
긴 답변을 보여줄 때 사용자의 체감 대기 시간을 줄일 수 있다.
8. JSON 응답은 후속 처리를 쉽게 만든다
AI 답변을 사람이 읽기만 한다면 자연어 문장으로 받아도 된다.
하지만 서비스 로직에서 AI 응답을 사용하려면 구조화된 응답이 필요하다.
예를 들어 고객 문의를 AI가 분류한다고 해보자.
AI가 이렇게 답하면 사람이 읽기에는 괜찮다.
이 문의는 결제 관련 문의로 보입니다. 중요도는 높습니다.
하지만 서버 코드에서 처리하기에는 애매하다.
분류값이 어디에 있는지, 중요도가 어떤 값인지 파싱하기 어렵다.
이럴 때는 JSON 형식으로 응답을 받는 것이 좋다.
{
"category": "payment",
"priority": "high",
"summary": "사용자가 결제 후 충전 내역이 반영되지 않았다고 문의함"
}
이렇게 받으면 서버에서 바로 처리할 수 있다.
category가 payment이면 결제 담당 큐로 이동
priority가 high이면 우선 처리
summary는 상담 화면에 표시
AI에게 JSON 응답을 요청할 때는 형식을 명확히 주는 것이 좋다.
아래 고객 문의를 분류해줘.
반드시 다음 JSON 형식으로만 응답해줘.
{
"category": "payment | login | broadcast | refund | other",
"priority": "low | medium | high",
"summary": "문의 요약"
}
고객 문의:
하트를 충전했는데 반영이 안 돼요.
다만 중요한 점이 있다.
AI가 JSON으로 답하라고 해도 항상 완벽한 JSON이 온다고 보장할 수는 없다.
예를 들어 다음처럼 앞뒤에 설명을 붙일 수 있다.
아래는 JSON 결과입니다.
{
"category": "payment",
"priority": "high",
"summary": "하트 충전 후 반영되지 않음"
}
또는 따옴표가 빠지거나, 허용하지 않은 값이 들어올 수도 있다.
그래서 서버에서는 반드시 검증해야 한다.
AI 응답 수신
→ JSON 파싱
→ 필수 필드 확인
→ 허용된 값인지 확인
→ 실패하면 재요청 또는 기본 처리
운영 환경에서는 스키마 검증을 사용하는 것이 좋다.
스키마는 데이터가 어떤 구조와 타입을 가져야 하는지 정의한 규칙이다.
예를 들어 category는 문자열이고, payment/login/refund 중 하나여야 한다는 식으로 검증할 수 있다.
9. 에러 처리는 반드시 필요하다
AI API도 외부 API다.
따라서 항상 성공한다고 가정하면 안 된다.
실제 운영 환경에서는 다양한 문제가 발생할 수 있다.
- API 호출 실패
- 네트워크 timeout
- 인증 오류
- 요청 제한 초과
- 모델 응답 지연
- 잘못된 요청 형식
- 응답 파싱 실패
- AI 서비스 장애
예를 들어 사용자가 AI 요약 버튼을 눌렀는데 AI API가 실패할 수 있다.
이때 아무 처리 없이 오류가 터지면 사용자 경험이 나빠진다.
서비스에서는 실패 상황을 미리 설계해야 한다.
AI 요약 요청
→ 성공하면 요약 표시
→ 실패하면 안내 메시지 표시
→ 필요하면 재시도 버튼 제공
→ 서버 로그에 실패 원인 기록
사용자에게는 너무 기술적인 메시지를 보여줄 필요가 없다.
나쁜 예:
OpenAI API request failed with 429 rate_limit_exceeded
좋은 예:
현재 AI 요약을 생성하지 못했습니다.
잠시 후 다시 시도해주세요.
하지만 서버 로그에는 상세 정보를 남겨야 한다.
- 요청 ID
- 사용자 ID 또는 관리자 ID
- 호출한 모델
- 에러 코드
- 응답 시간
- 재시도 여부
- 입력 데이터 크기
에러 유형별 대응도 다르게 해야 한다.
| 에러 유형 | 대응 |
|---|---|
| 네트워크 timeout | 짧은 재시도 후 실패 처리 |
| 요청 제한 초과 | 일정 시간 후 재시도 또는 사용자 제한 |
| 인증 오류 | 서버 설정 확인 필요 |
| 잘못된 요청 | 프롬프트 또는 파라미터 검토 |
| 응답 파싱 실패 | 재요청 또는 기본값 처리 |
| AI 서비스 장애 | fallback 모델 또는 안내 메시지 |
AI API는 일반 API보다 응답 시간이 길 수 있고, 실패 원인도 다양하다.
따라서 에러 처리는 선택이 아니라 필수다.
timeout은 요청을 보낸 뒤 일정 시간 안에 응답이 오지 않으면 실패로 처리하는 것이다.
AI API는 응답 시간이 길어질 수 있으므로 적절한 timeout 설정이 필요하다.
10. 재시도는 조심해서 사용해야 한다
외부 API가 실패하면 재시도를 떠올리기 쉽다.
일시적인 네트워크 문제라면 재시도가 도움이 될 수 있다.
하지만 AI API에서는 재시도를 무조건 많이 하면 안 된다.
이유는 간단하다.
재시도도 비용이 발생하기 때문이다.
예를 들어 하나의 AI 요청이 실패했고, 서버가 자동으로 3번 재시도한다고 해보자.
원래 요청 1회
+ 재시도 3회
= 최대 4회 비용 발생 가능
사용자가 많으면 비용이 빠르게 증가할 수 있다.
또 요청 제한 초과 상태에서 계속 재시도하면 상황이 더 나빠질 수 있다.
재시도는 에러 유형에 따라 다르게 해야 한다.
재시도가 도움이 될 수 있는 경우:
- 일시적인 네트워크 오류
- 순간적인 timeout
- 일시적인 서버 오류
재시도해도 소용없는 경우:
- API Key 오류
- 요청 형식 오류
- 권한 오류
- 입력 데이터가 너무 큼
재시도를 할 때는 보통 짧은 간격으로 여러 번 때리는 것보다,
점점 간격을 늘리는 방식이 좋다.
1차 실패
→ 1초 후 재시도
→ 실패
→ 3초 후 재시도
→ 실패
→ 최종 실패 처리
이런 방식을 exponential backoff라고 부른다.
운영 환경에서는 재시도 횟수를 제한해야 한다.
- 최대 재시도 횟수 설정
- 재시도 가능한 에러만 재시도
- 전체 timeout 제한
- 실패 로그 기록
- 사용자에게 명확한 안내
AI API는 비용이 발생하는 외부 의존성이다.
재시도는 안정성을 높일 수 있지만, 잘못 설계하면 비용과 장애를 키울 수 있다.
exponential backoff는 실패할 때마다 재시도 간격을 점점 늘리는 방식이다.
외부 API 장애나 일시적 오류에 대응할 때 자주 사용한다.
11. 비용을 추적해야 한다
AI API는 사용량 기반 비용이 발생하는 경우가 많다.
그래서 AI 기능을 운영할 때는 비용 추적이 반드시 필요하다.
처음 테스트할 때는 비용이 작게 보일 수 있다.
하지만 사용자가 늘어나거나 입력 데이터가 길어지면 비용이 빠르게 증가한다.
예를 들어 고객 문의 요약 기능을 생각해보자.
하루 요약 요청 수: 10,000건
요청당 평균 입력 토큰: 1,500
요청당 평균 출력 토큰: 300
하루 토큰 사용량은 다음과 같다.
입력 토큰:
10,000 × 1,500 = 15,000,000 tokens
출력 토큰:
10,000 × 300 = 3,000,000 tokens
한 달이면 훨씬 커진다.
월 입력 토큰:
15,000,000 × 30 = 450,000,000 tokens
월 출력 토큰:
3,000,000 × 30 = 90,000,000 tokens
이제 모델 단가를 곱하면 월 비용을 추정할 수 있다.
따라서 서비스에서는 요청 단위로 사용량을 기록하는 것이 좋다.
기록하면 좋은 정보:
- 사용자 또는 관리자 ID
- 기능명
- 모델명
- 입력 토큰
- 출력 토큰
- 총 토큰
- 응답 시간
- 성공/실패 여부
- 요청 시각
이 정보를 저장하면 다음을 알 수 있다.
- 어떤 기능이 비용을 많이 쓰는가
- 어떤 사용자가 많이 사용하는가
- 평균 입력 길이가 얼마나 되는가
- 모델 변경 후 비용이 줄었는가
- 비정상적으로 긴 요청이 있는가
비용을 줄이는 방법도 있다.
- 입력 문서를 줄인다.
- 답변 길이를 제한한다.
- 반복 요청은 캐싱한다.
- 간단한 작업은 저렴한 모델을 사용한다.
- 사용자별 사용량 제한을 둔다.
- 긴 문서는 RAG로 필요한 부분만 전달한다.
AI API 비용은 눈에 보이지 않게 증가할 수 있다.
그래서 처음부터 비용 추적 구조를 넣어두는 것이 좋다.
12. 로그를 남기되 민감 정보는 보호해야 한다
AI API를 운영하려면 로그가 필요하다.
문제가 생겼을 때 원인을 확인하려면 요청과 응답 정보를 어느 정도 기록해야 한다.
하지만 AI 요청에는 민감 정보가 포함될 수 있다.
예를 들어 고객 문의 요약 기능이라면 고객의 개인정보가 들어갈 수 있다.
이름, 이메일, 전화번호, 결제 내역, 상담 내용
코드 리뷰 기능이라면 회사 내부 코드가 들어갈 수 있다.
운영 로그 분석 기능이라면 서버 IP, 토큰, 내부 URL이 포함될 수 있다.
그래서 AI 로그는 조심해서 설계해야 한다.
무조건 전체 요청과 응답을 저장하면 위험하다.
위험한 로그:
- 사용자 원문 전체 저장
- AI 요청 프롬프트 전체 저장
- AI 응답 전체 저장
- API Key 포함 로그
- 개인정보가 포함된 에러 로그
대신 목적에 따라 필요한 정보만 남기는 것이 좋다.
권장 로그:
- 요청 ID
- 기능명
- 모델명
- 토큰 사용량
- 응답 시간
- 성공/실패 여부
- 에러 코드
- 마스킹된 입력 일부
필요하다면 원문은 저장하지 않고 해시나 요약만 저장할 수도 있다.
원문 저장:
위험할 수 있음
마스킹 후 저장:
개인정보 일부 제거
메타데이터만 저장:
비용과 성능 분석에는 충분할 수 있음
예를 들어 로그는 다음처럼 남길 수 있다.
{
"requestId": "ai_req_123",
"feature": "customer_summary",
"model": "example-model",
"inputTokens": 1200,
"outputTokens": 250,
"latencyMs": 3200,
"status": "success",
"createdAt": "2026-05-03T10:00:00Z"
}
이 정도 정보만으로도 비용, 성능, 장애 분석에 도움이 된다.
민감 정보가 필요한 디버깅 상황이라면 별도 권한과 보관 기간을 둬야 한다.
- 접근 권한 제한
- 보관 기간 제한
- 개인정보 마스킹
- 다운로드 제한
- 조회 로그 기록
AI 기능은 데이터를 외부 모델에 보내고 응답을 받는 구조가 많기 때문에,
로그 정책을 처음부터 신중하게 잡아야 한다.
해시는 원본 값을 일정한 규칙으로 변환한 값이다.
원문을 그대로 저장하지 않고 동일 여부를 확인하거나 추적할 때 사용할 수 있다.
13. 모델을 직접 호출하지 말고 중간 계층을 두는 것이 좋다
작은 테스트에서는 서비스 코드에서 AI API를 바로 호출해도 된다.
하지만 운영 서비스에서는 AI 호출을 담당하는 중간 계층을 두는 것이 좋다.
예를 들어 좋지 않은 구조는 다음과 같다.
회원 서비스 코드 → OpenAI API 직접 호출
관리자 서비스 코드 → OpenAI API 직접 호출
배치 코드 → OpenAI API 직접 호출
이렇게 되면 문제가 생긴다.
- 모델을 바꾸기 어렵다.
- 공통 에러 처리가 어렵다.
- 비용 추적이 분산된다.
- 로그 정책이 제각각이 된다.
- API Key 관리가 어려워진다.
- 사용량 제한을 공통으로 적용하기 어렵다.
더 나은 구조는 AI 호출을 담당하는 별도 계층을 두는 것이다.
서비스 코드
→ AI Gateway
→ AI Provider
AI Gateway는 AI 호출을 공통으로 처리하는 내부 모듈 또는 서버다.
AI Gateway 역할:
- 모델 선택
- 프롬프트 템플릿 관리
- API Key 관리
- 토큰 사용량 기록
- 에러 처리
- 재시도 정책
- 응답 검증
- fallback 처리
- 로그 마스킹
예를 들어 서비스 코드는 이렇게 요청할 수 있다.
{
"feature": "customer_summary",
"input": {
"message": "고객 문의 원문..."
}
}
AI Gateway는 내부에서 적절한 모델과 프롬프트를 선택한다.
customer_summary 기능
→ 저렴하고 빠른 요약 모델 사용
→ 개인정보 마스킹 적용
→ 3문장 이내 요약 프롬프트 사용
→ 결과 저장
나중에 모델을 바꾸고 싶을 때도 서비스 코드를 크게 고치지 않아도 된다.
기존:
OpenAI 모델 사용
변경:
Bedrock 모델 또는 로컬 모델로 교체
서비스 코드:
그대로 유지
AI 기능이 늘어날수록 중간 계층의 중요성은 커진다.
처음부터 거창한 플랫폼을 만들 필요는 없지만,
적어도 AI 호출 코드를 공통 모듈로 분리하는 것이 좋다.
AI Gateway는 여러 AI 모델 호출을 공통 인터페이스로 감싸는 계층이다.
모델 교체, 비용 추적, 에러 처리, 보안 정책을 한곳에서 관리하기 쉽게 해준다.
14. 프롬프트 템플릿을 관리해야 한다
AI API를 서비스에 붙이면 프롬프트도 코드처럼 관리해야 한다.
처음에는 프롬프트를 코드 안에 문자열로 직접 넣을 수 있다.
const prompt = `
아래 고객 문의를 3줄로 요약해줘.
고객 문의:
${message}
`;
작은 기능에서는 괜찮다.
하지만 기능이 많아지면 관리가 어려워진다.
- 프롬프트가 코드 곳곳에 흩어진다.
- 수정 이력을 추적하기 어렵다.
- 어떤 프롬프트가 운영 중인지 알기 어렵다.
- A/B 테스트가 어렵다.
- 모델 변경 시 프롬프트를 함께 조정하기 어렵다.
그래서 프롬프트 템플릿을 관리하는 방식이 필요하다.
예를 들어 다음처럼 템플릿을 분리할 수 있다.
prompts/
customer-summary.md
code-review.md
incident-report.md
inquiry-classifier.md
고객 문의 요약 프롬프트는 다음처럼 관리할 수 있다.
당신은 고객센터 상담 내용을 요약하는 도우미입니다.
아래 고객 문의를 3문장 이내로 요약하세요.
조건:
- 고객이 겪는 문제를 먼저 작성하세요.
- 개인정보는 포함하지 마세요.
- 추정은 하지 마세요.
고객 문의:
{{message}}
서버에서는 {{message}} 부분에 실제 데이터를 넣는다.
프롬프트 템플릿을 관리하면 다음이 좋아진다.
- 프롬프트 수정 이력을 남길 수 있다.
- 기능별 프롬프트를 분리할 수 있다.
- 운영 중인 프롬프트 버전을 관리할 수 있다.
- 모델별 프롬프트를 다르게 사용할 수 있다.
- 테스트와 개선이 쉬워진다.
프롬프트는 단순한 문장이 아니라 서비스 품질에 영향을 주는 로직이다.
따라서 코드처럼 버전 관리하고 리뷰하는 것이 좋다.
15. 간단한 AI API 호출 예시
이제 간단한 AI API 호출 구조를 코드로 살펴보자.
아래 예시는 특정 AI 제공사에 종속되지 않는 형태의 의사 코드에 가깝다.
async function callAiApi({model, messages, temperature, maxTokens}) {
const response = await fetch("https://api.example-ai.com/v1/chat", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.AI_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model,
messages,
temperature,
max_tokens: maxTokens
})
});
if (!response.ok) {
throw new Error(`AI API request failed: ${response.status}`);
}
const data = await response.json();
return data.choices[0].message.content;
}
이 코드는 기본적인 구조를 보여준다.
1. API URL로 POST 요청을 보낸다.
2. Authorization 헤더에 API Key를 넣는다.
3. model, messages, 옵션을 body에 넣는다.
4. 응답이 실패하면 에러를 발생시킨다.
5. 응답 JSON에서 AI 답변을 꺼낸다.
하지만 운영 코드로는 부족하다.
실제 서비스에서는 다음을 더 추가해야 한다.
- timeout
- 재시도 정책
- 에러 유형 분리
- 토큰 사용량 기록
- 응답 검증
- 로그 마스킹
- fallback 처리
- API Key 누락 검사
조금 더 실무적으로는 다음처럼 감쌀 수 있다.
async function generateCustomerSummary(message) {
const maskedMessage = maskPersonalInfo(message);
const messages = [
{
role: "system",
content: "너는 고객 문의를 요약하는 상담 지원 도구다."
},
{
role: "user",
content: `
아래 고객 문의를 3문장 이내로 요약해줘.
조건:
- 개인정보는 포함하지 마.
- 추정하지 마.
- 고객이 겪는 문제를 먼저 작성해.
고객 문의:
${maskedMessage}
`
}
];
const result = await callAiApi({
model: "example-ai-model",
messages,
temperature: 0.2,
maxTokens: 300
});
return result;
}
이 예시에서 중요한 부분은 AI API를 직접 호출하기 전에 개인정보를 마스킹했다는 점이다.
const maskedMessage = maskPersonalInfo(message);
AI 기능은 코드 몇 줄로 만들 수 있다.
하지만 운영 가능한 AI 기능은 에러 처리, 보안, 비용 추적까지 포함해야 한다.
16. AI API를 사용할 때의 기본 설계 흐름
AI API 기능을 만들 때는 다음 순서로 설계하면 좋다.
1. 기능 목적 정의
2. 입력 데이터 확인
3. 민감 정보 포함 여부 확인
4. 사용할 모델 선택
5. 프롬프트 템플릿 작성
6. 출력 형식 정의
7. 응답 검증 로직 작성
8. 에러 처리와 재시도 설계
9. 비용 추적 설계
10. 로그 정책 정의
11. 운영 테스트
예를 들어 고객 문의 요약 기능이라면 다음처럼 정리할 수 있다.
1. 기능 목적
고객 문의 내용을 상담원이 빠르게 파악할 수 있도록 요약한다.
2. 입력 데이터
고객 문의 본문, 문의 유형, 작성 시간
3. 민감 정보
이메일, 전화번호, 결제 정보 포함 가능
4. 모델
요약 품질이 좋은 빠른 모델 사용
5. 프롬프트
3문장 이내, 개인정보 제외, 추정 금지
6. 출력 형식
텍스트 또는 JSON
7. 응답 검증
빈 응답, 너무 긴 응답, 개인정보 포함 여부 확인
8. 에러 처리
실패 시 "요약 생성 실패" 표시
9. 비용 추적
관리자 ID, 기능명, 토큰 사용량 기록
10. 로그 정책
원문 저장 금지, 메타데이터만 저장
이렇게 정리한 뒤 개발하면 기능이 훨씬 안정적이다.
AI API는 호출 자체보다 운영 설계가 중요하다.
17. AI API를 처음 붙일 때 자주 하는 실수
AI API를 처음 사용할 때 자주 하는 실수가 있다.
첫 번째는 프론트엔드에서 직접 AI API를 호출하는 것이다.
브라우저 JavaScript
→ AI API 직접 호출
이 방식은 위험하다.
API Key가 사용자 브라우저에 노출될 수 있기 때문이다.
AI API는 보통 백엔드 서버에서 호출해야 한다.
브라우저
→ 우리 백엔드
→ AI API
두 번째는 입력 데이터를 그대로 보내는 것이다.
고객 문의, 로그, 코드에는 민감 정보가 있을 수 있다.
AI API에 보내기 전에 마스킹이나 필터링이 필요하다.
세 번째는 비용 제한 없이 기능을 여는 것이다.
사용자가 긴 문서를 계속 넣거나 자동화된 요청이 반복되면 비용이 크게 늘 수 있다.
네 번째는 실패 처리를 하지 않는 것이다.
AI API가 실패했을 때 사용자에게 이상한 오류가 보이거나, 기능 전체가 멈출 수 있다.
다섯 번째는 AI 응답을 그대로 신뢰하는 것이다.
AI가 JSON으로 답했는지, 허용된 값만 반환했는지, 개인정보가 포함되지 않았는지 검증해야 한다.
정리하면 다음과 같다.
자주 하는 실수:
- 프론트엔드에서 API Key 노출
- 민감 정보 그대로 전송
- 비용 제한 없음
- timeout과 재시도 없음
- 응답 검증 없음
- 로그에 원문 전체 저장
- 모델 교체를 고려하지 않은 구조
이 실수들은 초기에는 잘 드러나지 않을 수 있다.
하지만 운영 환경에서는 보안 사고, 비용 폭증, 장애로 이어질 수 있다.
18. 정리
AI API는 우리 서비스와 AI 모델을 연결하는 통로다.
사용자가 직접 AI 도구를 사용하는 것이 아니라,
우리 서비스가 AI 모델을 호출해 요약, 분류, 번역, 코드 분석, 문서 생성 같은 기능을 제공할 수 있게 해준다.
AI API 요청에는 보통 모델, 메시지, 옵션, 출력 형식이 들어간다.
응답에는 AI가 생성한 답변과 토큰 사용량, 상태 정보가 포함된다.
대화형 AI API에서는 system, user, assistant 같은 역할을 가진 메시지를 사용한다.
대화 이력을 유지하려면 서버가 이전 메시지를 관리해야 한다.
temperature는 답변의 다양성을 조절하고,
max tokens는 답변 길이를 제한한다.
스트리밍 응답은 긴 답변을 보여줄 때 체감 속도를 높인다.
운영 환경에서는 단순 호출보다 다음이 더 중요하다.
- 에러 처리
- 재시도 정책
- 비용 추적
- 민감 정보 보호
- 로그 정책
- 응답 검증
- 프롬프트 템플릿 관리
- AI Gateway 구조
AI API는 몇 줄의 코드로 호출할 수 있다.
하지만 안정적으로 운영하려면 API 호출 주변의 설계가 필요하다.
이 장에서 기억해야 할 핵심은 하나다.
AI API 개발은 “AI에게 질문 보내기”가 아니라,
AI 응답을 안전하고 예측 가능하게 서비스에 연결하는 작업이다.
8장 핵심 요약
| 핵심 내용 | 설명 |
|---|---|
| AI API는 서비스와 AI 모델을 연결한다 | 백엔드 서버가 AI 모델을 호출해 요약, 분류, 번역, 코드 분석 같은 기능을 만들 수 있다. |
| 요청과 응답 구조를 이해해야 한다 | 모델, 메시지, 옵션, 출력 형식, 토큰 사용량을 함께 봐야 한다. |
| 메시지는 role과 content로 구성된다 | system, user, assistant 역할을 사용해 대화 구조를 만든다. |
| 대화 이력은 서버가 관리해야 한다 | API는 이전 대화를 자동으로 기억하지 않으므로 필요한 메시지를 함께 보내야 한다. |
| temperature는 다양성을 조절한다 | 정확성이 중요한 작업은 낮게, 아이디어 작업은 조금 높게 설정할 수 있다. |
| max tokens는 출력 길이를 제한한다 | 비용, 속도, UI를 고려해 답변 길이를 통제해야 한다. |
| 스트리밍 응답은 체감 속도를 높인다 | 긴 답변을 사용자에게 보여줄 때 생성되는 내용을 조금씩 표시할 수 있다. |
| JSON 응답은 후속 처리를 쉽게 만든다 | 분류, 추출, 자동화 기능에서는 구조화된 응답이 유용하다. |
| 에러 처리와 재시도는 필수다 | AI API도 실패할 수 있으므로 timeout, 재시도, fallback을 설계해야 한다. |
| 비용과 로그를 추적해야 한다 | 토큰 사용량, 응답 시간, 성공/실패 여부를 기록해 운영 비용과 품질을 관리해야 한다. |
| AI Gateway 구조가 유용하다 | 모델 교체, 보안, 비용 추적, 에러 처리를 공통으로 관리할 수 있다. |
| 프롬프트는 코드처럼 관리해야 한다 | 기능별 템플릿, 버전 관리, 리뷰 과정을 두면 품질 관리가 쉬워진다. |